﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using API.Models.Repository;
using System.Threading.Tasks;

namespace API.Controllers
{
    public class SecurityController : AsyncController
    {
        //
        // GET: /Security/

        private API.Models.SEC_SESSIONS GetSession(string api_key)
        {
            var sessionRepository = new SEC_SESSIONS_Repository();
            var ip = Request.RequestContext.HttpContext.Request.UserHostAddress;
            return sessionRepository.LogIn(ip, api_key);
        }


        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Login(string email, string password, string api_key)
        {
            var sessionRepository = new SEC_SESSIONS_Repository();
            var session = new API.Models.SEC_SESSIONS();

            var ip = Request.RequestContext.HttpContext.Request.UserHostAddress;

            if (String.IsNullOrEmpty(api_key))
            {
                session = sessionRepository.LogIn(ip, email, password);
            }
            else
            {
                session = sessionRepository.LogIn(ip, api_key);
            }

            if (session == null)
                throw new Exception("Сессия не найдена");

            if (session.USER != null)
                session.USER.PASSWORD_HASH = null;

            var api_session = new API.Models.API_SESSION
            {
                APIKEY = session.APIKEY,
                COMPANY_GUID = session.COMPANY_GUID, //.GetValueOrDefault(),
                COMPANY_KEY = session.COMPANY != null ? session.COMPANY.EXT_KEY : String.Empty,
                COMPANYNAME = session.COMPANY != null ? session.COMPANY.COMPANY_NAME : "Компания не выбрана",
                EMAIL = session.USER.EMAIL,
                LOGON_DATETIME = session.LOGON_DATETIME,
                USER_GUID = session.USER_GUID,
                USER = session.USER
            };

            return Json(api_session, JsonRequestBehavior.AllowGet);
        }

        public ActionResult ChangeCompany(string api_key, Guid company_key)
        {
            var sessionRepository = new SEC_SESSIONS_Repository();
            var companyRepository = new SEC_USER_COMPANIES_Repository();

            var session = sessionRepository.GetSession(api_key);
            companyRepository.SetSession(session);

            if (!companyRepository.Find().Any(r => r.COMPANY_GUID == company_key && r.IS_ALLOWED))
                throw new Exception("Доступ к компании не предоставлен");

            session.COMPANY_GUID = company_key;

            sessionRepository.Edit(session);
            sessionRepository.Save();

            return Content("ОК");
        }

        public ActionResult AccessToUser(string email, Guid company_key)
        {
            var userRepository = new SEC_USERS_Repository();
            var userCompanyRepository = new SEC_USER_COMPANIES_Repository();
            var companyRepository = new WH_COMPANIES_Repository();

            var user = userRepository.Find(r => r.EMAIL == email).SingleOrDefault();
            var company = companyRepository.Find(r => r.GUID_RECORD == company_key).SingleOrDefault();

            if (company == null)
                throw new Exception("Компания не найдена");

            if (user == null)
            {
                var genPasswordLength = int.Parse(System.Configuration.ConfigurationManager.AppSettings["genPasswordLength"]);
                var password = API.Core.Util.PasswordGenerator(genPasswordLength, false);
                user = userRepository.Register(email, password);

                this.SendNewRegisterMail(email, password);
            }

            if (userCompanyRepository.Find(r =>
                r.USER_GUID == user.GUID_RECORD &&
                r.COMPANY_GUID == company.GUID_RECORD &&
                r.IS_ALLOWED).Any())
            {
                throw new Exception(String.Format("Доступ пользователю {0} уже был предоставлен", email));
            }

            var access = new Models.SEC_USER_COMPANIES{
                COMPANY_GUID = company.GUID_RECORD,
                GUID_RECORD = Guid.NewGuid(),
                IS_ALLOWED = true,
                SECURITY_CODE = "0000",
                USER_GUID = user.GUID_RECORD
            };

            userCompanyRepository.Add(access);
            userCompanyRepository.Save();

            this.SendNewAccessMail(email, company.COMPANY_NAME);

            return Content("ОК");
        }

        /// <summary>
        /// Для предоставления доступа к компании
        /// формируется секретный код и высылается оператору на электронный адрес
        /// </summary>
        /// <param name="api_key"></param>
        /// <returns></returns>
        public ActionResult AccessToCompany(string api_key)
        {
            var session = GetSession(api_key);
            if (session == null)
                throw new Exception("Сессия не найдена");

            var repository = new SEC_COMPANIES_ACCESS_REQUESTS_Repository();
            repository.SetSession(session);

            var password = API.Core.Util.PasswordGenerator(5, false);
            repository.ProvideAccess(password);

            this.SendProvideAccessMail(
                session.USER.EMAIL, session.COMPANY.COMPANY_NAME, password);

            return Content("ОК");
        }

        /// <summary>
        /// Для получения доступа к компании
        /// оператор указывает секретный код
        /// </summary>
        /// <param name="api_key"></param>
        /// <param name="code"></param>
        /// <returns></returns>
        public ActionResult AccessToCompanyUseKey(string api_key, string code)
        {
            var session = GetSession(api_key);
            if (session == null)
                throw new Exception("Сессия не найдена");

            var repository = new SEC_COMPANIES_ACCESS_REQUESTS_Repository();
            repository.SetSession(session);
            repository.UseAccess(code);

            //this.SendUseAccessMail(
            //    session.USER.EMAIL, access.COMPANY.COMPANY_NAME);

            return Content("ОК");
        }

        /// <summary>
        /// Активации доступа к компании
        /// </summary>
        /// <param name="api_key"></param>
        /// <param name="id"></param>
        /// <returns></returns>
        public ActionResult AccessToCompanyConfirm(string api_key, Guid id)
        {
            var session = GetSession(api_key);
            if (session == null)
                throw new Exception("Сессия не найдена");

            var repository = new SEC_COMPANIES_ACCESS_REQUESTS_Repository();
            repository.SetSession(session);
            repository.ConfirmAccess(id);

            var record = repository.Find(r => r.ACCESS_GUID.Value.Equals(id)).SingleOrDefault();

            this.SendConfirmAccessMail(
                session.USER.EMAIL, record.COMPANY.COMPANY_NAME);

            return Content("ОК");
        }


        private void SendProvideAccessMail(string email, string name, string password)
        {
            var subject = "Предоставление доступа";
            var message = @"<h3>Уважаемый пользователь</h3><br/>Для получения доступа к справочникам компании " + name + " необходимо активировать код " + password  + "<br/>";

            new Core.EdexMail().Send(email, subject, message);

            //Task.Factory.StartNew(() =>
            //{
            //    this.SendAsyncMail(email, subject, String.Format(message, name, password));
            //});
        }

        private void SendUseAccessMail(string email, string name)
        {
            throw new NotImplementedException();
        }

        private void SendConfirmAccessMail(string email, string name)
        {
            var subject = "Предоставление доступа";
            var message = @"<h3>Уважаемый пользователь</h3><br/>Доступ к справочникам компании " + name + " предоставлен<br/>";

            new Core.EdexMail().Send(email, subject, message);

            //Task.Factory.StartNew(() =>
            //{
            //    this.SendAsyncMail(email, subject, String.Format(message, name));
            //});
        }

        private void SendNewRegisterMail(string email, string password)
        {
            var subject = "Регистрация";
            var message = @"<h3>Уважаемый пользователь</h3><br/>Ваш адрес электронный почты был указан при регистрации на портале системы электронного документооборота<br/>E-mail: " + email + "<br/>Пароль: " + password;

            new Core.EdexMail().Send(email, subject, message);

            //Task.Factory.StartNew(() =>
            //{
            //    this.SendAsyncMail(email, subject, String.Format(message, name, email, password));
            //});
        }

        private void SendNewAccessMail(string email, string companyName)
        {
            var subject = "Предоставление доступа";
            var message = @"<h3>Уважаемый пользователь</h3><br/>Вам был предоставлен доступ администратора компании " + companyName;

            new Core.EdexMail().Send(email, subject, message);

            //Task.Factory.StartNew(() =>
            //{
            //    this.SendAsyncMail(email, subject, String.Format(message, companyName));
            //});
        }
        
        /*
        [HttpPost]
        public async Task<ActionResult> Register(string email, string name)
        {
            var genPasswordLength = int.Parse(System.Configuration.ConfigurationManager.AppSettings["genPasswordLength"]);

            var repository = new SEC_USERS_Repository();
            var password = API.Core.Util.PasswordGenerator(genPasswordLength, false);
            repository.Register(email, name, password);

            this.SendNewRegisterMail(email, name, password);

            return await Task<ActionResult>.Factory.StartNew(() =>
            {
                return this.Login(email, password, String.Empty);
            });
        }

        [HttpPost]
        public async Task<ActionResult> Register(string email, string name, string password)
        {
            var repository = new SEC_USERS_Repository();
            repository.Register(email, name, password);

            this.SendNewRegisterMail(email, name, password);

            return await Task<ActionResult>.Factory.StartNew(() =>
            {
                return this.Login(email, password, String.Empty);
            });
        }
        */

        [HttpPost]
        public async Task<ActionResult> Register(API.Models.SEC_USERS user)
        {
            var repository = new SEC_USERS_Repository();
            repository.Register(user);

            this.SendNewRegisterMail(user.EMAIL, user.PASSWORD);

            return await Task<ActionResult>.Factory.StartNew(() =>
            {
                return this.Login(user.EMAIL, user.PASSWORD, String.Empty);
            });
        }

        
        //public async Task<ActionResult> Reset(string email)
        [HttpPost]
        public ActionResult Reset(string email)
        {
            var genPasswordLength = int.Parse(System.Configuration.ConfigurationManager.AppSettings["genPasswordLength"]);

            var repository = new SEC_USERS_Repository();
            var password = API.Core.Util.PasswordGenerator(genPasswordLength, false);
            repository.ResetPassword(email, password);

            var subject = "Изменение учетных данных";
            var message = @"<h3>Уважаемый пользователь</h3><br/>Ваш пароль в системе электронного документооборота был изменен<br/>E-mail: " + email + "<br/>Пароль: " + password;

            new Core.EdexMail().Send(email, subject, message);

            return Content("OK");
        }

        public ActionResult ChangePassword(string password, string new_password, string api_key)
        {
            var session = GetSession(api_key);
            if (session == null)
                throw new Exception("Сессия не найдена");

            var repository = new SEC_USERS_Repository();
            repository.SetSession(session);
            repository.ChangePassword(new_password);

            var subject = "Изменение учетных данных";
            var message = @"<h3>Уважаемый пользователь</h3><br/>Ваш пароль в системе электронного документооборота был изменен<br/>E-mail: " + session.USER.EMAIL + "<br/>Пароль: " + password;

            new Core.EdexMail().Send(session.USER.EMAIL, subject, message);
            return Content("OK");
        }

        public ActionResult ChangeUserInfo(API.Models.SEC_USERS user, string api_key)
        {
            var session = GetSession(api_key);
            if (session == null)
                throw new Exception("Сессия не найдена");

            var repository = new SEC_USERS_Repository();
            repository.SetSession(session);

            repository.Edit(user);
            repository.Save();

            return Content("OK");
        }

    }
}
